---
title: "MCP Client"
description: "Connect external MCP servers to extend browser-use with additional tools and integrations"
icon: "plug"
---

The MCP (Model Context Protocol) client allows browser-use agents to connect to external MCP servers, automatically exposing their tools as actions.

<Note>
  MCP is an open protocol for integrating LLMs with external data sources and tools. Learn more at [modelcontextprotocol.io](https://modelcontextprotocol.io).
</Note>

<Info>
  Looking to expose browser-use as an MCP server instead? See [MCP Server](/customize/mcp-server).
</Info>

## Installation

```bash
uv pip install "browser-use[cli]"
```

## Quick Start

```python
import os
from browser_use import Agent, Controller
from browser_use.mcp.client import MCPClient

# Create controller
controller = Controller()

# Connect to MCP server
mcp_client = MCPClient(
    server_name="filesystem",
    command="npx",
    args=["@modelcontextprotocol/server-filesystem", "/path/to/files"]
)

# Connect and register
await mcp_client.connect()
await mcp_client.register_to_controller(controller)

# Agent can now use filesystem tools
agent = Agent(
    task="Read the README.md file",
    controller=controller
)
await agent.run()

# Clean up
await mcp_client.disconnect()
```

## API Reference

### MCPClient

```python
class MCPClient:
    def __init__(
        self,
        server_name: str,
        command: str,
        args: list[str] | None = None,
        env: dict[str, str] | None = None,
    ) -> None
```

**Parameters:**
- `server_name`: Name of the MCP server (for logging)
- `command`: Command to start the server (e.g., `"npx"`)
- `args`: Arguments for the command
- `env`: Environment variables for the server

**Key Methods:**

```python
# Connect to server
await mcp_client.connect()

# Register tools to controller
await mcp_client.register_to_controller(
    controller,
    tool_filter=['read_file', 'write_file'],  # Optional
    prefix='fs_'  # Optional prefix
)

# Disconnect
await mcp_client.disconnect()
```

### Context Manager Usage

```python
async with MCPClient(
    server_name="github",
    command="npx",
    args=["@modelcontextprotocol/server-github"],
    env={"GITHUB_TOKEN": os.getenv("GITHUB_TOKEN")}
) as client:
    await client.register_to_controller(controller)
    await agent.run()
# Automatically disconnected
```

## Common MCP Servers

### Filesystem
```python
MCPClient(
    server_name="filesystem",
    command="npx",
    args=["@modelcontextprotocol/server-filesystem", "/path"]
)
```

### PostgreSQL
```python
MCPClient(
    server_name="postgres",
    command="npx",
    args=["@modelcontextprotocol/server-postgres", "postgresql://localhost/db"]
)
```

### GitHub
```python
MCPClient(
    server_name="github",
    command="npx",
    args=["@modelcontextprotocol/server-github"],
    env={"GITHUB_TOKEN": os.getenv("GITHUB_TOKEN")}
)
```

## Multiple Servers

Connect multiple servers with prefixes to avoid conflicts:

```python
# Filesystem server
fs_client = MCPClient(
    server_name="filesystem",
    command="npx",
    args=["@modelcontextprotocol/server-filesystem", "."]
)
await fs_client.connect()
await fs_client.register_to_controller(controller, prefix="fs_")

# GitHub server
gh_client = MCPClient(
    server_name="github",
    command="npx",
    args=["@modelcontextprotocol/server-github"],
    env={"GITHUB_TOKEN": os.getenv("GITHUB_TOKEN")}
)
await gh_client.connect()
await gh_client.register_to_controller(controller, prefix="gh_")

# Agent can use both
agent = Agent(
    task="Read README.md and create a GitHub issue",
    controller=controller
)
await agent.run()

# Clean up
await fs_client.disconnect()
await gh_client.disconnect()
```

## Tool Filtering

Register only specific tools:

```python
await mcp_client.register_to_controller(
    controller,
    tool_filter=['read_file', 'list_directory']
)
```

## Custom MCP Server

Create your own MCP server:

```python
# my_server.py
import mcp.server.stdio
import mcp.types as types
from mcp.server import Server

server = Server("custom-tools")

@server.list_tools()
async def handle_list_tools() -> list[types.Tool]:
    return [
        types.Tool(
            name="calculate",
            description="Perform calculation",
            inputSchema={
                "type": "object",
                "properties": {
                    "expression": {"type": "string"}
                },
                "required": ["expression"]
            }
        )
    ]

@server.call_tool()
async def handle_call_tool(name: str, arguments: dict) -> list[types.TextContent]:
    if name == "calculate":
        result = eval(arguments["expression"])
        return [types.TextContent(type="text", text=str(result))]
    return []

# Run server
async def main():
    async with mcp.server.stdio.stdio_server() as (read, write):
        await server.run(read, write, ...)

if __name__ == "__main__":
    import asyncio
    asyncio.run(main())
```

Connect custom server:

```python
custom_client = MCPClient(
    server_name="custom",
    command="python",
    args=["my_server.py"]
)
```

## Best Practices

1. **Always disconnect** when done
2. **Use prefixes** when connecting multiple servers
3. **Filter tools** to limit capabilities
4. **Use context managers** for automatic cleanup


## See Also

- [MCP Server](/customize/mcp-server) - Expose browser-use as an MCP server
- [Custom Functions](/customize/custom-functions) - Write custom actions directly
- [Model Context Protocol](https://modelcontextprotocol.io) - MCP specification
